// ml278
// Copyright (C) 2008 Bjørn Øivind Bjørnsen, Aleksander Gjermundsen, Knut Andre Tidemann, Thomas Hansen
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

#ifndef __PLANETARYPAGELODJOINT_H_
#define __PLANETARYPAGELODJOINT_H_

#include <OgreMaterialManager.h>
#include <OgreRenderable.h>
#include <OgreMovableObject.h>
#include "planetarycommon.h"

namespace Ogre
{
	class PlanetarySceneManager;
	class PlanetaryOptions;

	class PlanetaryPageLODJoint : public Renderable, public MovableObject
	{
	public:
		/// Constructor
		/// @param mgr Pointer to the scene manager
		PlanetaryPageLODJoint(PlanetarySceneManager *mgr);

		/// Initialise the joint
		/// @param parentZone The zone responsible to handle this joint. The Zone with the smallest LOD level is always handling the joints
		/// @param parentPageX X-Index for the parent page
		/// @param parentPageZ Z-Index for the parent page
		/// @param neighbourZone The neighbour zone to stich a seam to.
		/// @param neighbourPageX X-Index for the neighbour page
		/// @param neighbourPageZ Z-Index for the neighbour page
		/// @param relation The relation between the two zones, i.e is the neigbour NORTH,SOUTH,EAST or WEST of the parent.
		/// @param pNode The Scene Node to attach the renderable to
		void init(unsigned int planet,unsigned int parentZone, unsigned int parentPageX,unsigned int parentPageZ, unsigned int neighbourZone, unsigned int neighbourPageX,unsigned int neighbourPageZ,NEIGHBOUR relation,SceneNode *pNode);

		/// Loads the vertex data into the joint, using the information passed to init.
		void load();

		/// Frees up the data
		void unload();

		/// Uninitialises all variables that have been initialised.
		void uninit();

		/// Show or hide the joint
		/// @param show Set to true to show the joint
		void show(bool show);

		// MovableObject overridden methods
		/// Internal method overriden from MovableObject. Is called before each frame
		/// @param cam The current camera that will be used during the rendering
		virtual void _notifyCurrentCamera(Camera* cam);
		/// Internal method overriden from MovableObject. Called when the object is attached to a node.
		/// @param parent The node the joint got attached to
		virtual void _notifyAttached(Node* parent, bool isTagPoint = false);

		/// Internal method overriden from MovableObject. Adds this object's render operation to the rendering queue
		virtual void _updateRenderQueue(RenderQueue* queue);
		/// Internal method overriden from MovableObject. Sets this object's rendering operation parameters
		virtual void getRenderOperation(RenderOperation& rend);

		/// Internal method overriden from MovableObject. Gets the type name of this class
		virtual const String &getMovableType() const
		{
			return mType;
		}

		/// Internal method overriden from MovableObject. Gets the bounding box of this object
		virtual const AxisAlignedBox &getBoundingBox() const
		{
			return mBounds;
		}
		/// Internal method overriden from MovableObject. Gets the bounding radius of this object
		virtual Real getBoundingRadius() const
		{
			return mBoundingRadius;
		}


		// Renderable overridden methods
		/// Internal method overriden from Rnederable. Gets the current material
		virtual const MaterialPtr &getMaterial() const
		{
			return mMaterial;
		}

		/// Internal method overriden from Renderable. Gets the current world transformation matrix
		virtual void getWorldTransforms(Matrix4 *xform) const;
		/// Internal method overriden from Renderable. Gets the world orientation.
		virtual const Quaternion &getWorldOrientation() const;
		/// Internal method overriden from Renderable. Gets the current world position
		virtual const Vector3 &getWorldPosition() const;
		/// Internal method overriden from Renderable.
		virtual Real getSquaredViewDepth(const Camera *cam) const;
		/// Internal method overriden from Renderable. Gets the list of lights
		virtual const LightList &getLights() const;


	private:
		/// True if the joint is loaded and ready to be rendered
		bool mIsLoaded;
		/// True if the joint has been initialised and are ready to be loaded
		bool mIsInit;

		/// Functions to load the parent vertices into the buffer if the zone is ZONE_UP
		void loadParentUp(const VertexElement* poselem, uchar *pBuffer,unsigned int vertexSize);
		/// Functions to load the parent vertices into the buffer if the zone is ZONE_DOWN
		void loadParentDown(const VertexElement* poselem, uchar *pBuffer,unsigned int vertexSize);
		/// Functions to load the parent vertices into the buffer if the zone is ZONE_FRONT
		void loadParentFront(const VertexElement* poselem, uchar *pBuffer,unsigned int vertexSize);
		/// Functions to load the parent vertices into the buffer if the zone is ZONE_BACK
		void loadParentBack(const VertexElement* poselem, uchar *pBuffer,unsigned int vertexSize);
		/// Functions to load the parent vertices into the buffer if the zone is ZONE_LEFT
		void loadParentLeft(const VertexElement* poselem, uchar *pBuffer,unsigned int vertexSize);
		/// Functions to load the parent vertices into the buffer if the zone is ZONE_RIGHT
		void loadParentRight(const VertexElement* poselem, uchar *pBuffer,unsigned int vertexSize);

		/// Functions to load the child vertices into the buffer if the zone is ZONE_UP
		void loadChildUp(const VertexElement* poselem, uchar *pBuffer,unsigned int vertexSize);
		/// Functions to load the child vertices into the buffer if the zone is ZONE_DOWN
		void loadChildDown(const VertexElement* poselem, uchar *pBuffer,unsigned int vertexSize);
		/// Functions to load the child vertices into the buffer if the zone is ZONE_FRONT
		void loadChildFront(const VertexElement* poselem, uchar *pBuffer,unsigned int vertexSize);
		/// Functions to load the child vertices into the buffer if the zone is ZONE_BACK
		void loadChildBack(const VertexElement* poselem, uchar *pBuffer,unsigned int vertexSize);
		/// Functions to load the child vertices into the buffer if the zone is ZONE_LEFT
		void loadChildLeft(const VertexElement* poselem, uchar *pBuffer,unsigned int vertexSize);
		/// Functions to load the child vertices into the buffer if the zone is ZONE_RIGHT
		void loadChildRight(const VertexElement* poselem, uchar *pBuffer,unsigned int vertexSize);

		/// The relation the parent has to the child. NORTH = Child is north of the parent
		NEIGHBOUR mRelation;

		/// Planet ID
		unsigned int mPlanet;

		/// Parent and neighbour zone ids
		unsigned int mParentZone,mNeighbourZone;
		unsigned int mParentPageX,mParentPageZ,mNeighbourPageX,mNeighbourPageZ;

		/// Pointer to scene manager
		PlanetarySceneManager *mSceneMgr;

		/// Pointer to options object
		PlanetaryOptions *mOptions;
		
		/// Planet scale
		Real mScale;

		/// Scene node this joint is attached to
		SceneNode *mSceneNode;

		/// Vertex data info
		VertexData *mVertexes;

		/// Index data info
		IndexData *mIndexes;

		/// MovableObject bounds
		AxisAlignedBox mBounds;

		/// MovableObject bounding radius
		Real mBoundingRadius;

		/// MovableObject type
		static String mType;

		/// Renderable material
		MaterialPtr mMaterial;

		/// Renderable center
		Vector3 mCenter;

		/// Whether light list need to re-calculate
		mutable bool mLightListDirty;

		/// Cached light list
		mutable LightList mLightList;
	};
}

#endif
